#include "affair.h"
#include "path_stack.h"

int UsrInfoInit(UsrInfo_t *pUsrInfo)
{
    pathStackInit(&pUsrInfo->pathStack);
    pUsrInfo->prefixPath = "/home/project_netdisk";
    return 0;
}

// 路径拼接--这里默认传的fileName是相对路径
static int get_full_path(UsrInfo_t pUsrInfo, const char *fileName, char *path_buf, int buf_size){
    int ret = get_abs_path(pUsrInfo, path_buf, buf_size);
    ERROR_CHECK(ret , -1, "get_abs_path");
    strcat(path_buf, "/");
    strcat(path_buf, fileName);
    return 0;
}

int cmd_ls(UsrInfo_t *pUsrInfo, char *list, int list_size){
    char temp_path1[1024] = {0};
    char temp_path2[1024] = {0};
    memset(list, 0, list_size);
    strncpy(temp_path1,pUsrInfo->prefixPath,strlen(pUsrInfo->prefixPath));
    pathStackPrintf(&pUsrInfo->pathStack,temp_path2);
    strcat(temp_path1,temp_path2);
    printf("temp_path 1 = %s\n",temp_path1);
    struct dirent **namelist;
    int n = scandir(temp_path1,&namelist,NULL,NULL);
    if (n < 0)
    {
        perror("scandir");
        snprintf(list, list_size, "无法打开目录: %s",temp_path2); //应该不会执行
        return -1;
    }

    printf("目录中共有 %d 个文件:\n", n - 2);
    
    //准备发送的内容的缓冲区
    int offset = 0; // 当前写入位置
    int remaining = list_size - 1;  //'\0'

    offset += snprintf(list + offset, remaining - offset, "目录 %s 内容:\n", temp_path2); //打印标题

    for(int i = 0;i < n; ++i)
    {
        if (strcmp(namelist[i]->d_name, ".") == 0 ||strcmp(namelist[i]->d_name, "..") == 0) {
              free(namelist[i]);
              continue;
        }   
        char entry_path[2048];
        snprintf(entry_path, sizeof(entry_path), "%s/%s", temp_path1, namelist[i]->d_name);//用真实路径（服务端）检测文件类型
        struct stat st;
        char *indent = "    "; // 缩进
        char *prefix = "";

        if (stat(entry_path, &st) == 0) {
            if (S_ISDIR(st.st_mode)) {
                prefix = "[目录] ";  //
            }
            else if (S_ISREG(st.st_mode)) {  // 判断是否为文件
                prefix = "[文件] ";       
            }

            char line[256];
            int line_len = snprintf(line, sizeof(line), "%s%s%s\n", indent, prefix, namelist[i]->d_name);//整合缩进，类型，以及文件名

            printf("%s", line);//输出到当前屏幕（客户端）

            // 输出到缓冲
            if (line_len > 0 && offset + line_len < remaining) {
                strncpy(list + offset, line, remaining - offset);
                offset += line_len;
            } else {
                // 空间不足时添加省略号
                strncpy(list + offset, "...\n", remaining - offset);
                offset = list_size - 1; // 跳到结尾
                break;
            }

            free(namelist[i]);//清理每一块
        }
    }
        free(namelist);
        list[offset] = '\0'; // 确保字符串结束

        if (offset < remaining - 50) { // 确保有足够空间
            offset += snprintf(list + offset, remaining - offset, "\n总计: %d 个条目\n", n - 2);
        }
    
    return 0;
}

int cmd_pwd(UsrInfo_t *pUsrInfo, char *pwd, int pwd_size)
{
    memset(pwd, 0, pwd_size);
    if(pUsrInfo->pathStack.stackSize)
        pathStackGet(&pUsrInfo->pathStack, pwd, pwd_size);
    else
        sprintf(pwd, "/");
    return 0;
}

int new_cmd_pwd(UsrInfo_t *pUsrInfo, char *pwd){
    pathStackPrintf(&pUsrInfo->pathStack,pwd);
    return 0;                                                                                                                
}

int cmd_puts(char *fileName,UsrInfo_t *pUsrInfo, int netfd){
    /* char* share_path=NULL; */

    //没有虚拟路径，服务端怎么找到名字是fileName的文件？
    char file_real_path[2048]={0};
    get_abs_path(*pUsrInfo, file_real_path, sizeof(file_real_path));
    strcat(file_real_path, "/");
    strcat(file_real_path,fileName);
    train_t train;
    memset(&train,0,sizeof(train));
    // recv(socket_fb,&train.length,sizeof(train.length),MSG_WAITALL);
    // recv(socket_fb,train.data,train.length,MSG_WAITALL);//这里不接收文件名，工人线程已经接收过了，fileName
    printf("file_real_path=%s\n",file_real_path);
    int file_fb=open(file_real_path,O_RDWR|O_CREAT|O_TRUNC,0666);
    ERROR_CHECK(file_fb,-1,"open");
    off_t filesize;
    recv(netfd,&train.length,sizeof(train.length),MSG_WAITALL);
    recv(netfd,&filesize,train.length,MSG_WAITALL);
    printf("filesize==%ld\n",filesize);
    bzero(&train,sizeof(train));
    off_t total=0;
    while(1){
        printf("%5.2lf%%\r",100.0*total/filesize);
        fflush(stdout);
        recv(netfd,&train.length,sizeof(train.length),MSG_WAITALL);
        if(total==filesize){
            printf("recv over\n");
            break;
        }
        total+=train.length;
        recv(netfd,train.value,train.length,MSG_WAITALL);//如果是最后的车头为0的时，接收会阻塞吗                                                                                                          
        write(file_fb,train.value,train.length);
        bzero(train.value,train.length);
    }
    printf("100.00%%\n");

    return 0;
}

int cmd_gets(char *fileName,UsrInfo_t* pUsrInfo, int netfd){
    //没有虚拟路径，服务端怎么找到名字是fileName的文件？
    char file_real_path[2048]={0};
    strcat(file_real_path,pUsrInfo->prefixPath);
    get_abs_path(*pUsrInfo, file_real_path, sizeof(file_real_path));
    strcat(file_real_path,"/");
    strcat(file_real_path,fileName);
    int file_fb=open(file_real_path,O_RDWR);
    ERROR_CHECK(file_fb,-1,"open");
    train_t train;
    train.length=strlen(fileName);
    memcpy(train.value,fileName,strlen(fileName));
    send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netfd,train.value,train.length,MSG_NOSIGNAL);//发文件名
    struct stat statbuf;
    fstat(file_fb,&statbuf);
    off_t filesize=statbuf.st_size;
    train.length=sizeof(filesize);
    memcpy(train.value,&filesize,sizeof(filesize));
    send(netfd,&train.length,sizeof(train.length),MSG_NOSIGNAL);
    send(netfd,train.value,train.length,MSG_NOSIGNAL);//发文件大小
    while(1){//发文件内容
        int ret=read(file_fb,train.value,sizeof(train.value));
        send(netfd,&ret,sizeof(train.length),MSG_NOSIGNAL);
        /* send(netfd,train.value,ret,MSG_NOSIGNAL);//放在这里为什么不像之前一样卡住呢 */
        if(ret==0){
            printf("send over\n");
            break;
        }
        send(netfd,train.value,ret,MSG_NOSIGNAL);
    }
    close(file_fb);

    return 0;
}

// int cmd_rm(char *fileName)
// {
//     return unlink(fileName);
// }

// int cmd_rmdir(char *dirName)
// {
//     return rmdir(dirName);
// }

// int cmd_mkdir(char *dirName)
// {
//     return mkdir(dirName, 0666);
// }

int cmd_rm(UsrInfo_t pUsrInfo, const char *fileName){
    char fullPath[FULLPATH_SIZE];
    int ret = get_full_path(pUsrInfo, fileName, fullPath, FULLPATH_SIZE);
    // ERROR_CHECK(ret, -1, "get_full_path");
    if(ret == -1)
        return -1;

    int fd = open(fullPath, O_RDONLY);
    // ERROR_CHECK(fd, -1, "rm");
    if(fd == -1)
        return -1;
    return unlink(fullPath);
}

int cmd_mkdir(UsrInfo_t pUsrInfo, const char *dirName){
    char fullPath[FULLPATH_SIZE];
    int ret = get_full_path(pUsrInfo, dirName, fullPath, FULLPATH_SIZE);
    // printf("full_path:%s\n",fullPath);
    // ERROR_CHECK(ret, -1, "get_full_path");
    if(ret == -1)
        return -1;

    // int fd = open(fullPath, O_RDWR | O_CREAT | O_TRUNC);
    // // ERROR_CHECK(fd, -1, "mkdir");
    // if(fd == -1)
    //     return -1;
    // int mkdir(const char *pathname, mode_t mode);
    return mkdir(fullPath, 0666);// 注意mode是8进制数字
}

int cmd_rmdir(UsrInfo_t pUsrInfo, const char *dirName){
    char fullPath[FULLPATH_SIZE];
    int ret = get_full_path(pUsrInfo, dirName, fullPath, FULLPATH_SIZE);
    // ERROR_CHECK(ret, -1, "get_full_path");
    if(ret == -1)
        return -1;

    int fd = open(fullPath, O_RDONLY);
    // ERROR_CHECK(fd, -1, "rmdir");
    if(fd == -1)
        return -1;
    return rmdir(fullPath);
}

// int cmd_cd(UsrInfo_t *pUsrInfo, char *path,char *real_path)
// {
//    struct stat st;
//    char temp_path[1024] = {0};
//    if(path[0] == '/' || path[0] == '~') //绝对路径
//    {
//        path[0] = '/';
//        memset(temp_path, 0 ,sizeof(temp_path));
//        strcpy(temp_path, real_path);
//        strcat(temp_path, path);
//        printf("absolute_path:%s\n",temp_path);
//        if(stat(temp_path,&st) != 0){
//            printf("目录不存在!\n");
//            return -1;
//        }
//        else // 路径合法
//        {
//            while(pUsrInfo->pathStack.stackSize) // 全部出栈
//            {
//                printf("pop\n");
//                pathStackPop(&pUsrInfo->pathStack);
//                printf("stack3:\n");
//                pathStackPrint(&pUsrInfo->pathStack); //打印栈
//            }
//            char *p = strtok(path, "/");
//            while(p) //重新入栈
//            {
//                if(strcmp(p,"..")) //如果不是..
//                {
//                    char dirName[128] ={0};
//                    dirName[0] = '/';
//                    strcat(dirName, p);
//                    pathStackPush(&pUsrInfo->pathStack, dirName);
//                    p = strtok(NULL, "/");
//                    printf("绝对路径，不是..时，stack:\n");
//                    pathStackPrint(&pUsrInfo->pathStack); //打印栈
//                }
//                else // 如果是..
//                {
//                    if(pUsrInfo->pathStack.stackSize>0) // 出栈一个目录
//                        pathStackPop(&pUsrInfo->pathStack);
//                    printf("绝对路径，是..时，stack:\n"); // 打印栈
//                    pathStackPrint(&pUsrInfo->pathStack); //打印栈
//                    p = strtok(NULL, "/");
//                }    
//            }
//        }
//    }
//    else //相对路径
//    {
//        memset(temp_path, 0 ,sizeof(temp_path));
//        strcpy(temp_path, real_path);
//        pathStack_t temp_stack;
//        pathStackInit(&temp_stack);
//        dirNode_t *curNode = pUsrInfo->pathStack.first;
//        for(int i = 0; i < pUsrInfo->pathStack.stackSize; ++i)
//        {
//            if(strcmp(curNode->dirName,".."))
//                strcat(temp_path, curNode->dirName);
//            else if(pUsrInfo->pathStack.stackSize>0)
//                pathStackPop(&pUsrInfo->pathStack);
//            curNode = curNode->next;
//        }
//        strcat(temp_path, "/");
//        strcat(temp_path, path);
//        printf("temp_path:%s\n", temp_path);
//        if(stat(temp_path,&st) != 0){
//            printf("目录不存在!\n");
//            return -1;
//        }
//        char *p = strtok(path, "/");
//        while(p)
//        {
//            if(strcmp(p,".."))
//            {
//                char dirName[128] ={0};
//                dirName[0] = '/';
//                strcat(dirName, p);
//                pathStackPush(&pUsrInfo->pathStack, dirName);
//                p = strtok(NULL, "/");
//                printf("相对路径，不是..时，stack:\n");
//                pathStackPrint(&pUsrInfo->pathStack); //打印栈
//            }
//            else
//            {
//                if(pUsrInfo->pathStack.stackSize>0)
//                    pathStackPop(&pUsrInfo->pathStack);
//                printf("相对路径，是..时，stack:\n");
//                pathStackPrint(&pUsrInfo->pathStack); //打印栈
//                p = strtok(NULL, "/");
//            }    
//        }
//    }
//    return 0;
// }

int cmd_cd(UsrInfo_t *pUsrInfo, char *path){
    // 1. 创建临时栈,判断路径是否存在，
    // 真实栈用来存储当前客户端的真实路径，
    // 临时栈也便于错误恢复
    pathStack_t temp_stack;
    pathStackInit(&temp_stack);
    
    // 2. 切割路径
    char *token = NULL;
    if (path[0] == '/') {
        // 绝对路径,临时栈直接使用
        token = strtok(path + 1, "/"); // 跳过开头的'/'
    } 
    else if (path[0] == '~') {
        // 家目录等同真实路径
        token = strtok(path + 1, "/"); // 跳过开头的'~'
    }
    else {
        // 相对路径，复制当前栈（客户端真实路径）到临时栈
        copyStack(&pUsrInfo->pathStack, &temp_stack);
        token = strtok(path, "/");
    }
    
    // 3. 处理路径组件
    while (token) {
        if(strcmp(token, "..") == 0) {
                pathStackPop(&temp_stack);      //空了弹栈函数不执行所以无事发生
        }
        else if(strcmp(token, ".") == 0){
            //无事发生
        } 
        else{
            // 复制字符串内容
            char *dir_copy = strdup(token);
            if (!dir_copy) {
                perror("内存分配失败");
                return -1;
            }
            pathStackPush(&temp_stack, dir_copy);  //压栈
        }
        token = strtok(NULL, "/");  //继续切割
    }
    // 4. 切割结束验证路径
    char temp_path1[512] = {0},temp_path2[512] = {0};
    strncpy(temp_path1,pUsrInfo->prefixPath,strlen(pUsrInfo->prefixPath));
    pathStackPrintf(&temp_stack,temp_path2);

    strcat(temp_path1,temp_path2);
    printf("temp_path1 = %s\n",temp_path1);
    struct stat st;
    if(stat(temp_path1, &st) != 0 || !S_ISDIR(st.st_mode)){//不是目录或者是文件
        printf("目录 %s 不存在!\n", temp_path1);
        return -1;
    }
    // 5. 存在更新用户栈和真实路径
    copyStack(&temp_stack, &pUsrInfo->pathStack);
    
    return 0;
}

int get_abs_path(UsrInfo_t UsrInfo, char *path_buf, int buf_size)
{
    char path_stack[1024] = {0};
    memset(path_buf, 0, buf_size);
    strcat(path_buf, UsrInfo.prefixPath);
    pathStackGet(&UsrInfo.pathStack, path_stack, sizeof(path_stack));
    strcat(path_buf, path_stack);
    return 0;
}